home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
Advanced I⁄O v2.3
/
Advanced i⁄o
/
endian_io.h
< prev
next >
Wrap
Text File
|
1996-02-02
|
7KB
|
228 lines
// This may look like C code, but it is really -*- C++ -*-
/*
************************************************************************
*
* Class Endian_IO
* to read integers of various sizes taking the byte order
* into account
* and bit-stream IO
*
* Two different byte orders are supported
* bigendian - most significant byte first
* littleendian - most significant byte last
*
* $Id: endian_io.h,v 2.1 1995/03/02 18:06:20 oleg Exp oleg $
*
************************************************************************
*/
#ifndef __GNUC__
#pragma once
#endif
#ifndef endian_io_h
#define endian_io_h
#ifdef __GNUC__
#pragma interface
#endif
#include <fstream.h>
#include "myenv.h"
#ifdef __GNUC__
#define _IOS_Bin_ ios::bin
#else
#define _IOS_Bin_ ios::binary
#endif
// Extension to 'ios' to keep byte order
// and stream sharing info
class EndianIOData : virtual public ios
{
enum { MSBfirst, LSBfirst } byte_order;
bool shared; // Was this stream shared with some other
// stream?
public:
// Means having this stream reference the same
// disk structure *and* the memory buffer
// as a_file
void share_with(EndianIOData& a_file);
void unshare(void); // Check for sharing and break it
EndianIOData(void) : byte_order(LSBfirst), shared(false) {}
~EndianIOData(void) { unshare(); }
void set_bigendian(void) // Most significant byte first
{ byte_order = MSBfirst; }
void set_littlendian(void) // Least significant byte first
{ byte_order = LSBfirst; }
bool q_MSBfirst(void) const { return byte_order == MSBfirst; }
bool was_shared(void) const { return shared; }
// Returns TRUE if something goes wrong
// with the I/O
bool operator ! () { return !good(); }
void error(const char *descr);
// Make sure the stream was opened successfully
void assert_open(const char * file_name);
};
// Class to read (binary) data from the input stream
// keeping in mind the byte order
class EndianIn : public EndianIOData, public ifstream
{
public:
EndianIn(void) {}
EndianIn(const char * file_name) : ifstream(file_name,ios::in|_IOS_Bin_)
{ assert_open(file_name); }
~EndianIn(void) { unshare(); }
// Open by example. File handle of
// 'file' is dup-ed, so closing the
// present file would not close 'file'
EndianIn(EndianIn& file) { share_with(file); }
void open(const char *name, int mode=ios::in|_IOS_Bin_)
{ ifstream::open(name,mode); assert_open(name); }
void close(void); // Close the stream breaking sharing if any
// The following I/O functions take
// the char string op_description
// that tells what this operation is for
// On error, this string is printed along
// with the error description
unsigned char read_byte(const char * op_description);
unsigned short read_short(const char * op_description);
unsigned long read_long(const char * op_description);
};
inline unsigned char EndianIn::read_byte(const char * op_description)
{
unsigned char c;
if( !get(c) )
error(op_description);
return c;
}
// Class to write (binary) data from the input stream
// keeping in mind the byte order
class EndianOut : public EndianIOData, public ofstream
{
public:
EndianOut(void) {}
EndianOut(const char * file_name)
: ofstream(file_name,ios::out|ios::trunc|_IOS_Bin_)
{ assert_open(file_name); }
~EndianOut(void) { unshare(); }
// Open by example. File handle of
// 'file' is dup-ed, so closing the
// present file would not close 'file'
EndianOut(EndianOut& file) { share_with(file); }
void open(const char *name, int mode=ios::out|ios::trunc|_IOS_Bin_, int prot=0644)
{ ofstream::open(name,mode); assert_open(name); }
void close(void); // Close the stream
// The following I/O functions take
// the char string op_description
// that tells what this operation is for
// On error, this string is printed along
// with the error description
// Note, the first operand of write_byte
// has to be specified as 'int' rather
// than 'unsigned char', as bizarre as
// it may seem. Otherwise, write_byte(0xff)
// results in the i/o error
// 'Inappropriate IOCTL for device'
// after some 2000-4000 writings such a byte.
void write_byte(const int item, const char * op_description = "");
void write_short(const unsigned short item, const char* op_description = "");
void write_long(const unsigned long item, const char * op_description = "");
};
/*
*------------------------------------------------------------------------
* Bit-stream Input-Output
* Note, bits are written in first-in first-out mode
*/
class BitIOBuffer
{
protected:
unsigned char buffer;
enum { largest_bit_in_buffer = (1<<7) };
unsigned char curr_bit_pos;
public:
BitIOBuffer(void) : buffer(0), curr_bit_pos(largest_bit_in_buffer) {}
};
class BitIn : BitIOBuffer, public EndianIn
{
public:
// This is a dummy constructor. Use open() function
// of EndianIO class to perform the actual opening
BitIn(void) {}
int get_bit(void); // Get a bit from the input stream
short get_short(void); // Get a short integer that was written
// using a variable size code
};
class BitOut : BitIOBuffer, public EndianOut
{
public:
// This is a dummy constructor. Use open() function
// of EndianIO class to perform the actual opening
BitOut(void) {}
~BitOut(void);
void put_bit(const char bit); // Write a bit into the output stream
void put_short(const short item); // Write a signed short integer
// using a variable size code
void close(void); // Close the stream
};
// Put a bit (0/1) into the bit stream
inline void BitOut::put_bit(const char bit)
{
if( bit )
buffer |= curr_bit_pos;
if( (curr_bit_pos>>=1) == 0 )
write_byte(buffer), curr_bit_pos = largest_bit_in_buffer, buffer = 0;
}
// Flush the bit buffer on closing the stream
inline void BitOut::close(void)
{
// If the buffer contains something
if( curr_bit_pos != largest_bit_in_buffer )
{
write_byte(buffer); // Flush the buffer
curr_bit_pos = largest_bit_in_buffer, buffer = 0;
}
EndianOut::close();
}
inline BitOut::~BitOut(void) { close(); }
// Read a bit from the bit stream
inline int BitIn::get_bit(void)
{
if( curr_bit_pos & largest_bit_in_buffer )
{
if( eof() )
error("Reading an 8-bit chunk");
get(buffer);
}
unsigned char bit_pos = curr_bit_pos;
if( (curr_bit_pos >>=1) == 0 )
curr_bit_pos = largest_bit_in_buffer;
return buffer & bit_pos ? 1 : 0;
}
#endif